package pimmodel;

import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * 
 * Klasse TerminList:<br>
 * Klasse fuer die Verwaltung einer Liste, <br>
 * die mit Elementen des Typs ITermin gefuellt ist.
 * 
 * @authors (Torsten Mansfeld, Thomas Schoenfeld)
 * @version (20120908_01)
 * 
 */
public class TerminList extends PimList implements ITerminList {
	
	// Meldungskonstanten
	private	static	final	String			ITERMIN			= "Das uebergebene Objekt ist nicht vom Typ ITERMIN.";
	private	static	final	String			TERMINNAME		= "Der uebergebene Terminname ist kein gueltiger String.";
	private	static	final	String			TERMINLISTE		= "Das uebergebene Objekt ist null.";
	
	
	
	// Instanzvariablen
	public 					List<ITermin>	terminliste;
	
	
	
	/**
	 * Standard-Konstruktor der Klasse TerminList
	 */
	public TerminList() {
		
		terminliste = new ArrayList<ITermin>();
		
	}

	/**
	 * Kopierkonstruktor der Klasse TerminList, erstellt tiefe Kopie
	 * 
	 * @param	ITerminList		die zu kopierende Terminliste	
	 * 
	 * @throws					NullPointerException falls das uebergebene Objekt null ist.
	 * @throws					IllegalArgumentException falls ein Listenelement nicht vom Typ ITermin ist. 
	 */
	public TerminList( ITerminList terminlisteNeu ) {
		
		this();
		
		if ( terminlisteNeu == null )
			throw new NullPointerException( ITERMIN );
		
		for ( ITermin termin : terminlisteNeu.getTerminliste() ) {			
			
			terminHinzufuegen( new Termin ( termin ) );
			
		}
		
	}
	
	

	// Getter und Setter Methoden

	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#getTerminliste()
	 */	
	@Override
	public List<ITermin> getTerminliste() {
		
		return this.terminliste;
		
	}

	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#setTerminliste(java.util.List)
	 */
	@Override
	public void setTerminliste( List<ITermin> terminliste ) {
		
		if ( terminliste == null )
			throw new NullPointerException( TERMINLISTE );
		
		this.terminliste = new ArrayList<ITermin>();
		
		for ( ITermin termin : terminliste ) {
			
			if ( !( termin instanceof ITermin ) )
				throw new IllegalArgumentException( ITERMIN );
		
			terminHinzufuegen( new Termin( termin ) );			
			
		}
		
		sortieren();
				
		this.setChanged();
		this.notifyObservers( terminliste );
		
	}
	
	
	
	// sonstige Methoden	

	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#terminErsetzen(pimmodel.ITermin, pimmodel.ITermin)
	 */	
	@Override
	public boolean terminErsetzen( ITermin bearTermin, ITermin orgTermin ) {
		
		if ( !( bearTermin instanceof ITermin ) || !( orgTermin instanceof ITermin ) )
			throw new IllegalArgumentException( ITERMIN );
		
		boolean ret = terminLoeschen( orgTermin );
		
		if ( ret )
			ret = terminHinzufuegen( bearTermin );
		
		return ret;
		
	}

	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#terminHinzufuegen(pimmodel.ITermin)
	 */
	@Override
	public boolean terminHinzufuegen( final ITermin neuTermin ) {
		
		if ( !( neuTermin instanceof ITermin ) )
			throw new IllegalArgumentException( ITERMIN );		
		
		boolean ret = terminliste.add( neuTermin );
		
		sortieren();
		
		this.setChanged();
		this.notifyObservers( neuTermin );
		
		return ret;
		
	}	
	
	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#terminLoeschen(pimmodel.ITermin)
	 */
	@Override
	public boolean terminLoeschen( final ITermin loeschTermin ) {
		
		if ( !( loeschTermin instanceof ITermin ) )
			throw new IllegalArgumentException( ITERMIN );
		
		boolean ret = this.terminliste.remove( loeschTermin );
		
		sortieren();
		
		this.setChanged();
		this.notifyObservers( loeschTermin );		
		
		return ret;
		
	}
	
	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#terminLiefern(int)
	 */
	@Override
	public ITermin terminLiefern( final int index ) {
		
		return this.terminliste.get( index );
		
	}	
	
	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#terminNameSuchen(java.lang.String)
	 */
	@Override
	public int terminNameSuchen( final String terminName ) {
		
		if ( !( terminName instanceof String ) || terminName.trim().isEmpty() )
			throw new IllegalArgumentException( TERMINNAME );	
		
		int index = -1; // 0 ist das erste Element!
		
		for( int i = 0; i < size(); i++ ){

			if ( terminName.trim().equals( terminLiefern( i ).getName() ) ) {
				
				index = i;
				
			}
			
		}
		
		return ( index );
		
	}
	
	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#terminSuchen(pimmodel.ITermin)
	 */
	@Override
	public int terminSuchen( final ITermin suchTermin ) {
		
		if ( !( suchTermin instanceof ITermin ) )
			throw new IllegalArgumentException( ITERMIN );	
				
		return this.terminliste.indexOf( suchTermin );
		
	}
	
	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#toArray()
	 */
	@Override
	public Object[] toArray() {
		
		return this.terminliste.toArray();
		
	}
	
	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#clear()
	 */
	@Override
	public void clear() {
		
		this.terminliste = new ArrayList<ITermin>();
		
		this.setChanged();
		this.notifyObservers( this.terminliste );
		
	}
	
	/**
	 * clone					liefert flache Kopie der Terminliste
	 * 
	 * @return					flache Kopie der Terminliste
	 */
	@Override
	public ITerminList clone() {
		
		return this;
		
	}
	
	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#isEmpty()
	 */
	@Override
	public boolean isEmpty() {
		
		return this.terminliste.isEmpty();
		
	}
	
	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#size()
	 */
	@Override
	public int size() {
		
		return this.terminliste.size();
		
	}
	
	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#toString()
	 */
	@Override
	public String toString() {
		
		String ausgabe = "";
		
		sortieren();
		
		for ( ITermin termin : this.terminliste ) {
			
			ausgabe += termin + "\n";
			
		}
		
		return ausgabe;
		
	}

	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#hashCode()
	 */
	@Override
	public int hashCode() {
		
		final int prime = 31;
		
		int result = 1;
		
		result = prime * result	+ ( ( this.terminliste == null ) ? 0 : this.terminliste.hashCode() );
		
		return result;
		
	}

	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#equals(java.lang.Object)
	 */
	@Override
	public boolean equals( final Object obj ) {
		
		if ( this == obj )
			return true;
		
		if ( obj == null )
			return false;
		
		if ( getClass() != obj.getClass() )
			return false;
		
		TerminList other = ( TerminList ) obj;
		
		if ( terminliste == null ) {
			if ( other.terminliste != null )
				return false;
		} 
		else if ( !terminliste.equals( other.terminliste ) )
			return false;
		
		return true;
		
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see pimmodel.ITerminList#speichern()
	 */
	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#speichern(java.lang.String)
	 */
	@Override
	public void speichern( final String dateiname ) throws FileNotFoundException, IOException {
		
		ObjectOutputStream outputStream = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream( dateiname ) ) );
		
		outputStream.writeObject( this.terminliste );
		
		outputStream.close();
		
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see pimmodel.ITerminList#laden()
	 */
	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#laden(java.lang.String)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public void laden( final String dateiname ) throws IOException, ClassNotFoundException {
		
		ObjectInputStream inputStream = new ObjectInputStream( new BufferedInputStream( new FileInputStream( dateiname ) ) );
		
		this.terminliste = ( List<ITermin> ) inputStream.readObject();
		
		inputStream.close();
		
	}	
	

	// interne Sortier-Methode
	/* (non-Javadoc)
	 * @see pimmodel.ITerminList#sortieren()
	 */
	@Override
	public void sortieren() {
		
		Collections.sort( this.terminliste );
      
	}

}
